// AdaBClassifier.cpp: implementation of the CAdaBClassifier class.
//
//////////////////////////////////////////////////////////////////////

#include "ASample.h"
#include "AdaBoost.h"
#include "PonPoff.h"
#include "AdaBClassifier.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAdaBClassifier::CAdaBClassifier()
{
	strcpy(m_strID, "AdaBoost");
}

CAdaBClassifier::~CAdaBClassifier()
{
	Clear();
}

void CAdaBClassifier::Clear()
{
	int nClassifiers = m_vpClassifiers.size();
	for (int i = 0; i < nClassifiers; i ++)
	{
		delete m_vpClassifiers[i];
	}
}

float CAdaBClassifier::Classify(CASample *pSample, const char flag)
{
	float	p,fAlpha = 0;
	int		nClassifiers = m_vpClassifiers.size();
	CAClassifier *pClassifier;

	for (int i = 0; i < nClassifiers; i ++)
	{
		pClassifier = m_vpClassifiers[i];
		p = pClassifier->Classify(pSample, flag);
		if (p > 0.5)
			fAlpha += m_vfAlpha[i];
	}

	if (flag == DETECT_TEXT)
		fAlpha = (fAlpha - m_fSumAlpha) * 2;
	else if (flag == DETECT_FACE)
	{
		if (fAlpha > m_fSumAlpha*0.98)
			fAlpha /= m_fSumAlpha * 2;
		else
			fAlpha = 0;
	}

	return fAlpha;
}

bool CAdaBClassifier::LoadFromFile(const char *strFileName)
{
	FILE *fp = fopen(strFileName, "rb");
	if (fp == NULL)
	{
		return false;
	}

	// clear the current cascade
	Clear();

	LoadFromFile(fp);

	fclose(fp);

	return true;
}

void CAdaBClassifier::LoadFromFile(FILE *fp)
{
	// Read classifier ID
	fread(&m_strID, sizeof(char), 20, fp);
	// read IDs of features used in the classifier
	// No features used at this level

	//read number of classifiers
	int nClassifiers;
	fread(&nClassifiers, sizeof(int), 1, fp);
	m_vpClassifiers.resize(nClassifiers);
	m_vfAlpha.resize(nClassifiers);
	//read each of the classifiers
	m_fSumAlpha = 0;
	for (int i = 0; i < nClassifiers; i ++)
	{
		fread(&m_vfAlpha[i], sizeof(float), 1, fp);
		m_fSumAlpha += m_vfAlpha[i];

		char strID[20];
		fread(strID, sizeof(char), 20, fp);
		fseek(fp, -20L, SEEK_CUR);
		
		CAClassifier *pClassifier;
		if (strcmp(strID, "PonPoff") == 0){
			pClassifier = new CPonPoff();
		}
		else{
			pClassifier = NULL; // Siyuan : suppress compiling error
		}

		pClassifier->LoadFromFile(fp);
		m_vpClassifiers[i] = pClassifier;
	}
	m_fSumAlpha /= 2;
}

bool CAdaBClassifier::SaveToFile(const char *strFileName)
{
	FILE *fp = fopen(strFileName, "wb");
	if (fp == NULL)
		return false;

	SaveToFile(fp);

	fclose(fp);

	return true;
}

void CAdaBClassifier::SaveToFile(FILE *fp)
{
	// Write classifier ID
	fwrite(&m_strID, sizeof(char), 20, fp);
	// Write IDs of features used in the classifier
	// No features used at this level

	//write number of classifiers
	int nClassifiers = m_vpClassifiers.size();
	fwrite(&nClassifiers, sizeof(int), 1, fp);
	//write each of the classifiers
	for (int i = 0; i < nClassifiers; i ++)
	{
		// write Weight
		fwrite(&m_vfAlpha[i], sizeof(float), 1, fp);
		CAClassifier *pClassifier = m_vpClassifiers[i];
		pClassifier->SaveToFile(fp);
	}
}


void CAdaBClassifier::Train(const char *strHFileName, CVPClassifier vpClassifiers, int nT, float fPPos)
{
	CAdaBoost ada(nT);
	ada.LoadBinH(strHFileName);
	ada.Boost(fPPos);
	ada.Verify();

	Clear();
	vfloat vfAlpha;
	vint vnClassifiers;
	ada.GetClassifiers(vfAlpha, vnClassifiers);
	nT = vfAlpha.size();
	m_vfAlpha = vfAlpha;
	m_fSumAlpha = 0;
	for (int i = 0; i < nT; i++)
	{
		m_fSumAlpha += vfAlpha[i];
		CAClassifier *pc = vpClassifiers[vnClassifiers[i]];
		CAClassifier *pcnew;
		if (strcmp(pc->m_strID, "PonPoff") ==0)
		{
			pcnew = new CPonPoff();
			*((CPonPoff*)pcnew) = *((CPonPoff*)pc);
		}

		m_vpClassifiers.push_back(pcnew);
	}
	m_fSumAlpha /= 2;
}
